package com.haieros.www.purerunshowsystem.socket;

import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import android.widget.Toast;
import com.alibaba.fastjson.JSON;
import com.haieros.www.purerunshowsystem.bean.OriginalData;
import com.haieros.www.purerunshowsystem.bean.SocketBean;
import com.haieros.www.purerunshowsystem.bean.UpdateBean;
import com.haieros.www.purerunshowsystem.bean.UpdateInfo;
import org.json.JSONException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by W520 on 2017/12/19.
 */

public class SocketUtils1 implements Parcelable {
    //context
    private static Context mContext;
    //Socket
    private static Socket mSocket;
    //接收数据线程
    private static ReadThread mReadThread;
    // 线程池
    private static ExecutorService mThreadPoolSend;
    //int与byte[]转换
    private static IntAndByteArr mIntAndByteArr;
    //SocketBean对象
    private static SocketBean mSocketBean;
    // 输入流对象
    static InputStream mInputStream;
    // 接收服务器发送过来的消息
    static String mReceiveMsg;
    //声明OnDataReceiveListener数据接收接口
    private static OnDataReceiveListener mOnDataReceiveListener;
    //发送服务器消息变量
    private static OutputStream mOutputStream;

    private SocketUtils1() {
    }

    /**
     * 静态内部类单例
     */
    private static class SingletonHolder {
        private static final SocketUtils1 mInstance = new SocketUtils1();
    }

    /**
     * 获取SDKUtils初始化,并初始化客户端&服务端
     *
     * @param context,socketBean
     * @return
     */
    public static SocketUtils1 getSDKUtilsInstance(Context context, final SocketBean socketBean) {
        mContext = context;
        mSocketBean = socketBean;
        // 初始单任务线程池
        mThreadPoolSend = Executors.newSingleThreadExecutor();
        //mIntAndByteArr初始化
        mIntAndByteArr = IntAndByteArr.getIntAndByteArr();
        if (mSocketBean != null) {
            //socket初始化
            SocketConn();
        } else {
            Toast.makeText(mContext, "socketBean为null，Socket初始化失败！", Toast.LENGTH_SHORT).show();
        }
        return SingletonHolder.mInstance;
    }

    /**
     * 是否有数据的监听
     *
     * @param mDataReceiveListener
     */
    public void setOnDataReceiveListener(OnDataReceiveListener mDataReceiveListener) {
        this.mOnDataReceiveListener = mDataReceiveListener;
    }

    /**
     * Socket连接
     */
    public static void SocketConn() {
        if (mSocketBean != null && mThreadPoolSend != null) {
            mThreadPoolSend.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        //Socket初始化
                        mSocket = new Socket(SocketBean.MHOST, SocketBean.MPORT);
                        Log.d("===", "-----isClose()---" + mSocket.isClosed() + "----isConnect()" + mSocket
                                .isConnected());
                        //接收数据线程初始化，并开启数据接受
                        mReadThread = new ReadThread();
                        mReadThread.start();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
//                    finally {
//                        if (mSocket.isClosed()||mSocket.isConnected()){
//                            //设置重连
//                            Log.d("===", "断开了------------");
//                            closeCS();
//                            Log.d("===", "断开了------------" + mSocket.isClosed());
//                            while (mSocket.isClosed()) {
//                                Log.d("===", "断开了内部------------" + mSocket.isClosed());
//                                closeCS();
//                                SocketConn();
//                                new Handler().postDelayed(new Runnable(){
//                                    public void run() {
//                                        //execute the task
//                                    }
//                                }, 3000);
//
//                            }
//                        }
//                    }
                }
            });
        }
    }

    /**
     * @return true socket连接成功，false 失败
     */
    public static final boolean isConnected() {
        if (mSocket != null) {
            return mSocket.isConnected();
        } else {
            return false;
        }
    }

    /**
     * @return 返回socket是否关闭。true 未关闭，false 关闭。
     */
    public static final boolean isClose() {
        if (mSocket != null) {
            return !mSocket.isClosed();
        } else {
            return false;
        }
    }

    /**
     * 获取升级信息
     */
    public void sendUpdateInfo(UpdateInfo updateInfo) {
        if (updateInfo != null) {
            String msg = JSON.toJSONString(updateInfo);
            Log.i("=======", "========" + msg);
            int len = msg.length();
            sendMSG(msg, len);
        }
    }

    /**
     * @param msg Json
     * @param len Json串长度
     */
    public void sendMSG(final String msg, final int len) {
        mThreadPoolSend.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Log.i("send=======", "=======" + msg);
                    if (isClose()) {
                        // 从Socket 获得输出流对象OutputStream
                        // 该对象作用：发送数据
                        mOutputStream = mSocket.getOutputStream();
                        //将整形int转化成byte[]
                        byte[] bytes1 = mIntAndByteArr.int2byte(len);
                        // 步骤2：写入需要发送的数据到输出流对象中  特别注意：数据的结尾加上换行符才可让服务器端的readline()停止阻塞
//                        mOutputStream.write((msg.toString()+"\n").getBytes("utf-8"));
                        byte[] bytes2 = (msg.toString()).getBytes("utf-8");
                        Log.i("====输入的数据===", "====输入的数据===" + byte2hex(mIntAndByteArr.byteMerger(bytes1, bytes2)));
                        mOutputStream.write(mIntAndByteArr.byteMerger(bytes1, bytes2));
//                        mOutputStream.write((msg.toString()).getBytes("utf-8"));
                        // 发送数据到服务端
                        mOutputStream.flush();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    //打印byte[]
    private static String byte2hex(byte[] buffer) {
        String h = "";

        for (int i = 0; i < buffer.length; i++) {
            String temp = Integer.toHexString(buffer[i] & 0xFF);
            if (temp.length() == 1) {
                temp = "0" + temp;
            }
            h = h + " " + temp;
        }

        return h;

    }

    private static ByteBuffer mRemainingBuf;

    /**
     * 接收 服务器消息
     */
    private static class ReadThread extends Thread {
        @Override
        public void run() {
            super.run();
            if (isClose()) {
                while (!isInterrupted()) {
                    OriginalData originalData = new OriginalData();
                    ByteBuffer headBuf = ByteBuffer.allocate(4);
                    headBuf.order(ByteOrder.BIG_ENDIAN);
                    try {
                        if (mSocket != null) {
//                            byte[] bytes = new byte[1024];
                            //读取字节流
                            mInputStream = mSocket.getInputStream();
                            //获取接收长度
//                            int len = mInputStream.read(bytes);
//                            Log.i("====length========", "==================" + len);
                            //len>0证明有数据
//                            if (len > 0) {
                            if (mRemainingBuf != null) {
                                mRemainingBuf.flip();
                                int length = Math.min(mRemainingBuf.remaining(), 4);
                                headBuf.put(mRemainingBuf.array(), 0, length);
                                if (length < 4) {
                                    //there are no data left
                                    mRemainingBuf = null;
                                    for (int i = 0; i < 4 - length; i++) {
                                        headBuf.put((byte) mInputStream.read());
                                    }
                                } else {
                                    mRemainingBuf.position(4);
                                }
                            } else {
                                for (int i = 0; i < headBuf.capacity(); i++) {
                                    headBuf.put((byte) mInputStream.read());
                                }
                            }
                            originalData.setHeadBytes(headBuf.array());
                            for (byte b : headBuf.array()){
                                Log.i("======","======"+b);
                            }

                            int bodyLength = getBodyLength(originalData.getHeadBytes(), ByteOrder.BIG_ENDIAN);
                            if (bodyLength > 0) {
                                if (bodyLength > 10 * 1024 * 1024) {//大于最大的读取容量,说明数据有问题
                                    Log.i("数据异常", "we can't read data bigger than===== " + 10 + "Mb");
                                }
                                ByteBuffer byteBuffer = ByteBuffer.allocate(bodyLength);
                                byteBuffer.order(ByteOrder.BIG_ENDIAN);
                                if (mRemainingBuf != null) {
                                    int bodyStartPosition = mRemainingBuf.position();
                                    int length = Math.min(mRemainingBuf.remaining(), bodyLength);
                                    byteBuffer.put(mRemainingBuf.array(), bodyStartPosition, length);
                                    mRemainingBuf.position(bodyStartPosition + length);
                                    if (length == bodyLength) {
                                        if (mRemainingBuf.remaining() > 0) {//there are data left
                                            mRemainingBuf = ByteBuffer.allocate(mRemainingBuf.remaining());
                                            mRemainingBuf.order(ByteOrder.BIG_ENDIAN);
                                            mRemainingBuf
                                                    .put(mRemainingBuf.array(), mRemainingBuf.position(),
                                                            mRemainingBuf.remaining());
                                        } else {//there are no data left
                                            mRemainingBuf = null;
                                        }
                                        //cause this time data from remaining buffer not from channel.
                                        originalData.setBodyBytes(byteBuffer.array());
                                        mReceiveMsg = new String(originalData.getBodyBytes());
                                        //判断数据类型
                                        if (mReceiveMsg.length() > 0) {
                                            try {
                                                org.json.JSONObject jsonObject = new org.json.JSONObject
                                                        (mReceiveMsg);
                                                if (jsonObject.has("daemon_version") && jsonObject.has
                                                        ("daemon_path")
                                                        && jsonObject.has("control_app_version") && jsonObject
                                                        .has("control_app_path")
                                                        && jsonObject.has("display_app_version") && jsonObject
                                                        .has("display_app_path")) {
                                                    //升级
                                                    mOnDataReceiveListener.onUpdateURL(JSON.parseObject(mReceiveMsg,
                                                            UpdateBean.class));
                                                }
                                            } catch (JSONException e) {
                                                e.printStackTrace();
                                            }
                                        }
                                        return;
                                    } else {//there are no data left in buffer and some data pieces in channel
                                        mRemainingBuf = null;
                                    }
                                }
                                readBodyFromChannel(byteBuffer);
                                originalData.setBodyBytes(byteBuffer.array());
                            } else if (bodyLength == 0) {
                                originalData.setBodyBytes(new byte[0]);
                            }else if (bodyLength < 0) {
                                //设置重连
                                Log.d("===", "断开了------------");
                                closeCS();
                                Log.d("===", "断开了------------" + mSocket.isClosed());
                                while (mSocket.isClosed()) {
                                    Log.d("===", "断开了内部------------" + mSocket.isClosed());
                                    closeCS();
                                    sleep(3000);
                                    SocketConn();
                                }
                                continue;
                            }
                            mReceiveMsg = new String(originalData.getBodyBytes());
                            //判断数据类型
                            if (mReceiveMsg.length() > 0) {
                                try {
                                    org.json.JSONObject jsonObject = new org.json.JSONObject
                                            (mReceiveMsg);
                                    if (jsonObject.has("daemon_version") && jsonObject.has
                                            ("daemon_path")
                                            && jsonObject.has("control_app_version") && jsonObject
                                            .has("control_app_path")
                                            && jsonObject.has("display_app_version") && jsonObject
                                            .has("display_app_path")) {
                                        //升级
                                        mOnDataReceiveListener.onUpdateURL(JSON.parseObject(mReceiveMsg,
                                                UpdateBean.class));
                                    }
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                }
                            }
//                            } else if (len == -1) {
//                                //设置重连
//                                Log.d("===", "断开了------------");
//                                closeCS();
//                                Log.d("===", "断开了------------" + mSocket.isClosed());
//                                while (mSocket.isClosed()) {
//                                    Log.d("===", "断开了内部------------" + mSocket.isClosed());
//                                    closeCS();
//                                    sleep(3000);
//                                    SocketConn();
//                                }
//                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static int getBodyLength(byte[] header, ByteOrder byteOrder) {
        if (header == null || header.length == 0) {
            return 0;
        }

        return BytesUtils.byte2Int(header);
    }

    /**
     * 将byte数组中的元素倒序排列
     */
    public static byte[] bytesReverseOrder(byte[] b) {
        int length = b.length;
        byte[] result = new byte[length];
        for (int i = 0; i < length; i++) {
            result[length - i - 1] = b[i];
        }
        return result;
    }

    private static void readBodyFromChannel(ByteBuffer byteBuffer) throws IOException {
        while (byteBuffer.hasRemaining()) {
            try {
                byte[] bufArray = new byte[50000];
                int len = mInputStream.read(bufArray);
                if (len < 0) {
                    break;
                }
                int remaining = byteBuffer.remaining();
                if (len > remaining) {
                    byteBuffer.put(bufArray, 0, remaining);
                    mRemainingBuf = ByteBuffer.allocate(len - remaining);
                    mRemainingBuf.order(ByteOrder.BIG_ENDIAN);
                    mRemainingBuf.put(bufArray, remaining, len - remaining);
                } else {
                    byteBuffer.put(bufArray, 0, len);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Log.i("SocketUtils", "read total bytes: " + BytesUtils.toHexStringForLog(byteBuffer.array()));
        Log.i("SocketUtils", "read total length:" + (byteBuffer.capacity() - byteBuffer.remaining()));
    }
//    private static class ReadThread extends Thread {
//        @Override
//        public void run() {
//            super.run();
//            if (isClose()) {
//                while (!isInterrupted()) {
//                    try {
//                        if (mSocket != null) {
//                            byte[] bytes = new byte[1024];
//                            //读取字节流
//                            mInputStream = mSocket.getInputStream();
//                            //获取接收长度
//                            int len = mInputStream.read(bytes);
//                            Log.i("==长度======", len + "-------");
//                            //len>0证明有数据
//                            if (len > 0) {
//                                if (mOnDataReceiveListener != null) {
//                                    mOnDataReceiveListener.onDataReceive(bytes, len);
//                                }
//                                //判断数据长度
//                                if (len > 4) {
//                                    //截取数据
//                                    mReceiveMsg = new String(bytes, 4, len - 4);
//                                    Log.i("==22======", BytesUtils.toHexStringForLog(bytes)+mReceiveMsg + "-------");
////                                    Log.i("==23======", BytesUtils.toHexStringForLog(new byte[]{bytes[0],bytes[1],
//// bytes[2],bytes[3]}) + "-------");
//                                    //判断数据类型
//                                    if (mReceiveMsg.length() > 0) {
//                                        try {
//                                            org.json.JSONObject jsonObject = new org.json.JSONObject(mReceiveMsg);
//                                            if (jsonObject.has("daemon_version")&&jsonObject.has("daemon_path")
//                                                    &&jsonObject.has("control_app_version") &&jsonObject.has
// ("control_app_path")
//                                                    &&jsonObject.has("display_app_version")&&jsonObject.has
// ("display_app_path")) {
//                                                //升级
//                                                mOnDataReceiveListener.onUpdateURL(JSON.parseObject(mReceiveMsg,
//                                                        UpdateBean.class));
//                                            }
//                                        } catch (JSONException e) {
//                                            e.printStackTrace();
//                                        }
//                                    }
//                                }
//                            } else if (len == -1) {
//                                //设置重连
//                                Log.d("===", "断开了------------");
//                                closeCS();
//                                Log.d("===", "断开了------------" + mSocket.isClosed());
//                                while (mSocket.isClosed()) {
//                                    Log.d("===", "断开了内部------------" + mSocket.isClosed());
//                                    closeCS();
//                                    sleep(3000);
//                                    SocketConn();
//                                }
//                            }
//                        }
//                        //每30毫秒接收一次
////                        sleep(RECEIVE_SLPEEP_MILLIS);
////                                byte[] byte2int = new byte[]{bytes[0],bytes[1],bytes[2],bytes[3]};
////                                int sub = IntAndByteArr.getIntAndByteArr().byte2int(byte2int);
////                                mReceiveMsg = new String
//// (bytes[0]+"-"+bytes[1]+"-"+bytes[2]+"-"+bytes[3]+"---"+sub+"---size:"+len);
//                    } catch (IOException e) {
//                        e.printStackTrace();
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                }
//            }
//        }
//    }

    /**
     * 断开客户端 & 服务器的连接
     */
    public static void closeCS() {

        try {
            if (isConnected()) {
                // 断开 客户端发送到服务器 的连接，即关闭输出流对象OutputStream
                if (mOutputStream != null) {
                    mOutputStream.close();
                }
                // 断开 服务器发送到客户端 的连接，即关闭输入流读取器对象BufferedReader
                if (mInputStream != null) {
                    mInputStream.close();
                }
                if (mReadThread != null) {
                    mReadThread.interrupt();
                }
                // 最终关闭整个Socket连接
                mSocket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    protected SocketUtils1(Parcel in) {
    }

    public static final Creator<SocketUtils1> CREATOR = new Creator<SocketUtils1>() {
        @Override
        public SocketUtils1 createFromParcel(Parcel in) {
            return new SocketUtils1(in);
        }

        @Override
        public SocketUtils1[] newArray(int size) {
            return new SocketUtils1[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
    }
}
